/*
 * Android NewsFeed Application is a project for the Technological Educational Institute of Athens.
 * It's purpose is to familiarise the Android SDK and development procedures to students.
 * 
 * 
 * Android NewsFeed version 0.00
 * 
 * $LastChangedDate: 2012-05-24 22:25:35 +0000 (Thu, 24 May 2012) $
 * $Author: snoopaki $
 * $Rev: 105 $
 */

package gr.teiath.newsfeed;

import java.sql.Date;

import gr.teiath.newsfeed.R;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.SimpleCursorAdapter.ViewBinder;
import android.widget.Toast;


public class NewsList extends Activity implements OnItemClickListener, OnScrollListener, OnCancelListener {

    public static final String tag = "NewsList";
    public static final String NEWS_RECEIVER_INTENT = "gr.teiath.newsfeed.NEWS_RECEIVER_INTENT";
    
    public static boolean FLAG_REFRESH = true;
    public static long NEWS_COUNT = 0;
    
    private static final IntentFilter newsReceiverFilter = new IntentFilter(NEWS_RECEIVER_INTENT);
    
    private static int LAST_ITEM = 0;
    
    private ListView listNews;
    private static SimpleCursorAdapter CURSOR_ADAPTER;
    private static Cursor CURSOR;
    private NewsfeedApplication newsfeed;
    private ProgressDialog dialog;
	private static NewsReceiver NEWS_RECEIVER;
	private static ReadContentTask READ_CONTENT_TASK;
	private static View FOOTER;
	private static ViewBinder VIEW_BINDER = new ViewBinder() {
		public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
			if(view.getId() != R.id.listDate) return false;
			
			((TextView) view).setText(DateFormat.format("dd/MM/yy", Date.valueOf(cursor.getString(columnIndex))));			
			return true;
		}
	};

	private static final String[] FROM = { "name", "date", "faculty_name" };
	private static final int[] TO = { R.id.listTitle, R.id.listDate, R.id.listDepartment };


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(tag, "****** NewsList // onCreate()");

        setContentView(R.layout.newslist);  
        
        //TODO Bug: Pattern muffled. Add bg pattern in code, not in xml
        listNews = (ListView) findViewById(R.id.listNews);
        FOOTER = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.loadinglistfooter, null, false);
        // myFeed = newsfeed.getFeed(parseURL);
        
        newsfeed = (NewsfeedApplication) getApplication();
        newsfeed.createDB(); // Create Database if it does not exist
        newsfeed.handleNetworkChange();
        
        CURSOR = newsfeed.readNewsList(LAST_ITEM);
		
		/** Cursor Adapter */ 
        CURSOR_ADAPTER = new SimpleCursorAdapter(this, R.layout.listrow, CURSOR, FROM, TO);
        CURSOR_ADAPTER.setViewBinder(VIEW_BINDER);
            
        listNews.addFooterView(FOOTER);
		listNews.setAdapter(CURSOR_ADAPTER);
		listNews.setOnItemClickListener(this); 
		listNews.setOnScrollListener(this);
		
		listNews.removeFooterView(FOOTER);

		NEWS_RECEIVER = new NewsReceiver();

    }
    
    public void onResume() {
    	super.onResume();
    	Log.i(tag, "****** NewsList // onResume()");
    	// TODO ?? Make an AsyncTask
    	if(!refreshList()) CURSOR_ADAPTER.changeCursor(CURSOR);
    	registerReceiver(NEWS_RECEIVER, newsReceiverFilter);
    	
    }
    
    private boolean refreshList() {
    	if(FLAG_REFRESH) {
	    	Log.i(tag, "****** NewsList // Refreshing...");
	    	CURSOR = newsfeed.readNewsList(0);
	    	CURSOR_ADAPTER.changeCursor(CURSOR);
	    	//FLAG_REFRESH = false;
	    	FLAG_REFRESH = true;
	    	return true;
    	}
    	return false;
    }
    
    public void onPause() {
    	super.onPause();
    	Log.i(tag, "****** NewsList // onPause()");
    	unregisterReceiver(NEWS_RECEIVER);
    }
    
    public void onDestroy() {
    	super.onDestroy();
    	CURSOR.close(); // Instead of startManagingCursor which is being deprecated in Android 3.0
    	Log.i(tag, "****** NewsList // onDestroy()");
    }
    
    @Override
    public void onBackPressed() {
    	moveTaskToBack(true);
    	return;
    }
    
    // TODO Bug: Scrollable List View when list items are few (less than screen area)
    // TODO Bug: Sometimes ListView is not clickable...
    //@Override
	public void onScroll(AbsListView view, int firstVisible, int visibleCount, int totalCount) {
    	// Check if more News items are needed
		if(NEWS_COUNT > 0 ) {
			Log.i(tag,"****** NewsList // NEWSCOUNT:" + NEWS_COUNT + ", totalCount:" + totalCount);
			if(totalCount >= NEWS_COUNT) {
				if(listNews.getFooterViewsCount() == 1) {
					Log.i(tag,"****** NewsList // REMOVE footer...");
					this.listNews.removeFooterView(FOOTER); // Remove the footer if no more data available
				}
			return;
			} else {
				if(listNews.getFooterViewsCount() == 0) {
					Log.i(tag,"****** NewsList // ADDING footer...");
					listNews.addFooterView(FOOTER); // Add a footer if more data is available
				}
			}
		}
		
    	if(totalCount > 0 && firstVisible + visibleCount >= totalCount) {
        	Log.i(tag,"****** NewsList // onScroll() Load More News!!!");
        	Log.i(tag,"****** NewsList // NEWSCOUNT:" + NEWS_COUNT + ", totalCount:" + totalCount);
        	LAST_ITEM = firstVisible + visibleCount;
        	LoadMoreNewsTask loadMoreNews = new LoadMoreNewsTask();
        	loadMoreNews.execute();
        }
	}

	//@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {}
    
    public void onItemClick(AdapterView<?> arg0, View arg1, int position, long id) {
    	CURSOR.moveToPosition(position);
    	READ_CONTENT_TASK = new ReadContentTask();
    	
    	if (READ_CONTENT_TASK.getStatus() != AsyncTask.Status.RUNNING) {
			if(CURSOR.getString(CURSOR.getColumnIndex("_content")) == null)
				// TODO Bug: Crash when orientation changes while progress dialog is showing
				dialog = ProgressDialog.show(this, this.getString(R.string.loadingListTitle), this.getString(R.string.loadingListMsg), true, true, this);

			READ_CONTENT_TASK.execute(
	    			CURSOR.getString(CURSOR.getColumnIndex("_id")), 
	    			CURSOR.getString(CURSOR.getColumnIndex("link")),
	    			CURSOR.getString(CURSOR.getColumnIndex("_content")),
	    			CURSOR.getString(CURSOR.getColumnIndex("p_type"))
	    			//cur.getString(cur.getColumnIndex("faculty_name"))
	    		);
    	}
    	
    }
    
    //@Override
	public void onCancel(DialogInterface dialog) {
    	if (READ_CONTENT_TASK != null) {
    		READ_CONTENT_TASK.cancel(true);
    	}
		
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu, menu);
		
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.itemPrefs:
			startActivity(new Intent(this, PrefsActivity.class));
			break;
		
		case R.id.itemRefresh:
			startService(new Intent(this, FetchService.class));
			break;
			
		case R.id.purgeDbThree:
			newsfeed.purgeDatabase(false);
			startActivity(new Intent(this, NewsList.class));
			break;
			
		case R.id.purgeDbAll:
			newsfeed.purgeDatabase(true);
			startActivity(new Intent(this, NewsList.class));
			break;
			
		case R.id.purgePrefs:
			newsfeed.purgePrefs();
			startActivity(new Intent(this, NewsList.class));
			break;
		}
		return true;
	}
	
	class LoadMoreNewsTask extends AsyncTask<String, Integer, Cursor> {

		@Override
		protected Cursor doInBackground(String... params) {
			final Cursor cur = newsfeed.readNewsList(NewsList.LAST_ITEM);
			
			return cur;
		}
		
		protected void onPostExecute(Cursor loadedNews) {
			NewsList.CURSOR = loadedNews;
			CURSOR_ADAPTER.changeCursor(loadedNews);
		}		
	}
	
	class ReadContentTask extends AsyncTask<String, Integer, Boolean> {

		private Feeder feed;
		private boolean isExternal = false;
		private boolean connectivity = true;
		private boolean hasData = true;
		private final NewsList parentContext = NewsList.this;  // Reference to the parent class
		private int parseType;
		
		@Override
		protected Boolean doInBackground(String... newsData) {
			this.parseType = Integer.parseInt(newsData[3]); // Read parse_type
			Log.i(tag, "****** NewsView // newsDaa[2]:" + newsData[2]);
			
			
			// TODO ?? Is "_external" really needed??
			if(newsData[2] == null) {
				this.hasData = false;
				if(NewsfeedApplication.getNetworkConnectivity()) {
					Log.i(NewsList.tag, "****** NewsView // hasContent is FALSE");
					
			        feed = newsfeed.newFeed(newsData[1], this.parseType); // Get Feed Link
			        feed.getContent();
			        
			        if (feed.contentMap.get("title") == null && feed.contentMap.get("content") == null) { // Second check after parsing if post isExternal
			        	Log.i(tag, "****** NewsView // no title & content");
			        	isExternal = true; // Check if feed has title & content
			        	newsfeed.writeIsExternal(newsData[0]); // Write isExternal to 1 in db
					} else {
				        // Write to db...
				        newsfeed.writeContent(newsData[0], feed.contentMap.get("content"));
			        }
				} else {
		    		connectivity = false;
		    		//NewsList.FLAG_REFRESH = true;
		    	}
			}
			return isExternal;
		}

		@Override
		protected void onPostExecute(Boolean isExternal) {
			super.onPostExecute(isExternal);
			if(dialog != null && dialog.isShowing()) dialog.dismiss();
			if(connectivity) {
				if(isExternal) { // Final check if post isExternal
		        	Log.i(tag, "****** NewsView // isExternal is TRUE");
					newsfeed.externalLink(CURSOR.getString(CURSOR.getColumnIndex("link")));
		        } else {
		        	Log.i(tag, "****** NewsView // isExternal is FALSE");
		        	
		        	Intent newsView = new Intent(parentContext, NewsView.class);
		        	newsView.putExtra("_id", CURSOR.getString(CURSOR.getColumnIndex("_id")));
		        	newsView.putExtra("link", CURSOR.getString(CURSOR.getColumnIndex("link")));
		        	newsView.putExtra("faculty_id", CURSOR.getString(CURSOR.getColumnIndex("faculty_id")));
		        	newsView.putExtra("p_type", this.parseType);
		        	//newsView.putExtra("external", cur.getInt(cur.getColumnIndex("external")) > 0 ? true : false );
		        	//newsView.putExtra("content", cur.getString(cur.getColumnIndex("content")) == null ? false : true);
		        	startActivity(newsView);
		        }
			} else {
				if(hasData) {
					Log.i(tag, "****** NewsView // hasData is TRUE");
		        	
		        	Intent newsView = new Intent(parentContext, NewsView.class);
		        	newsView.putExtra("_id", CURSOR.getString(CURSOR.getColumnIndex("_id")));
		        	newsView.putExtra("link", CURSOR.getString(CURSOR.getColumnIndex("link")));
		        	newsView.putExtra("faculty_id", CURSOR.getString(CURSOR.getColumnIndex("faculty_id")));
		        	newsView.putExtra("p_type", this.parseType);
		        	//newsView.putExtra("external", cur.getInt(cur.getColumnIndex("external")) > 0 ? true : false );
		        	//newsView.putExtra("content", cur.getString(cur.getColumnIndex("content")) == null ? false : true);
		        	startActivity(newsView);
				} else {
					
				Log.i(tag, "****** NewsView // hasData is FALSE");
		        	
				Toast.makeText(parentContext, parentContext.getText(R.string.noConnection), Toast.LENGTH_SHORT).show();
				}
			}
		}

		@Override
		protected void onCancelled() { Log.i(tag, "****** NewsList // Task Canceled!"); }
		
	}
	// TODO Add user-permissions for NewsReceiver
	class NewsReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			Log.i(tag, "****** NewsReceiver // New Items DETECTED!!!");
			try {
				CURSOR = newsfeed.readNewsList(LAST_ITEM);
				CURSOR_ADAPTER.changeCursor(CURSOR);
			} catch(Exception e) {
				Log.i(tag,"****** NewsReceiver // Exception: " + e);
			}
			
		}
		
	}
}